package com.youlu.campus.service.activity.impl;

import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.ActivityAutoTask;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.UserActivityTaskRankingAttach;
import com.youlu.campus.entity.VO.req.ActivityAutoTaskQueryVO;
import com.youlu.campus.entity.form.FormTaskConfig;
import com.youlu.campus.entity.form.UserFormTaskInfo;
import com.youlu.campus.service.activity.ActivityAutoTaskService;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.activity.UserActivityTaskRankingAttachService;
import com.youlu.campus.service.form.FormTaskConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

@Slf4j
@Service
public class ActivityAutoTaskServiceImpl implements ActivityAutoTaskService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Lazy
    @Autowired
    private ActivityService activityService;
    @Lazy
    @Autowired
    private UserActivityTaskRankingAttachService userActivityTaskRankingAttachService;
    @Lazy
    @Autowired
    private FormTaskConfigService formTaskConfigService;

    @Override
    public ActivityAutoTask create(ActivityAutoTask req) {
        if (StringUtils.isNotBlank(req.getId())) {
            req.setId(null);
        }
        if (Objects.isNull(req.getCreatedTime())) {
            req.setCreatedTime(new Date());
        }
        if (StringUtils.isNotBlank(req.getActivityId())) {
            ActivityInfo activityInfo = activityService.findOne(req.getActivityId());
            if (Objects.nonNull(activityInfo)) {
                req.setActivityName(activityInfo.getName());
            }
        }
        if (StringUtils.isNotBlank(req.getBizId())) {
            switch (req.getType()) {
                case "form":
                    FormTaskConfig form = formTaskConfigService.findOne(req.getBizId());
                    if (Objects.nonNull(form)) {
                        req.setBizName(form.getName());
                    }
                    break;
            }
        }
        return mongoTemplate.insert(req);
    }

    @Override
    public boolean update(ActivityAutoTask req) {
        Query q = new Query();
        q.addCriteria(Criteria.where("id").is(req.getId()));
        Update u = new Update();
        boolean toUpdate = false;
        if (StringUtils.isNotBlank(req.getType())) {
            u.set("type", req.getType());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getStatus())) {
            u.set("status", req.getStatus());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getName())) {
            u.set("name", req.getName());
            toUpdate = true;
        }
        if (Objects.nonNull(req.getQ())) {
            u.set("q", req.getQ());
            toUpdate = true;
        }
        if (Objects.nonNull(req.getStartTime())) {
            u.set("startTime", req.getStartTime());
            toUpdate = true;
        }
        if (Objects.nonNull(req.getEndTime())) {
            u.set("endTime", req.getEndTime());
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getActivityId())) {
            u.set("activityId", req.getActivityId());
            ActivityInfo activityInfo = activityService.findOne(req.getActivityId());
            if (Objects.nonNull(activityInfo)) {
                u.set("activityName", activityInfo.getName());
            }
            toUpdate = true;
        }
        if (StringUtils.isNotBlank(req.getBizId())) {
            u.set("bizId", req.getBizId());
            if (StringUtils.isNotBlank(req.getType())) {
                switch (req.getType()) {
                    case "form":
                        FormTaskConfig form = formTaskConfigService.findOne(req.getBizId());
                        if (Objects.nonNull(form)) {
                            u.set("bizName", form.getName());
                        }
                        break;
                    default:
                        break;
                }
            }
            toUpdate = true;
        }
        if (toUpdate) {
            u.set("updatedTime", new Date());
            return mongoTemplate.updateFirst(q, u, ActivityAutoTask.class).getModifiedCount() > 0 ? true : false;
        }
        return false;
    }

    @Override
    public ActivityAutoTask find(String activityId, String type) {
        if (StringUtils.isBlank(activityId) || StringUtils.isBlank(type)) {
            return null;
        }
        Query q = new Query();
        q.addCriteria(Criteria.where("activityId").is(activityId).and("type").is(type));
        return mongoTemplate.findOne(q, ActivityAutoTask.class);
    }

    @Override
    public ActivityAutoTask findOne(String id) {
        Query q = new Query();
        q.addCriteria(Criteria.where("id").is(id));
        return mongoTemplate.findOne(q, ActivityAutoTask.class);
    }

    @Override
    public boolean run(String id) {
        ActivityAutoTask a = this.findOne(id);
        if (Objects.isNull(a)) {
            log.error(":>>> 活动自动任务不存在:{}", id);
            throw new BusinessException("活动自动任务不存在");
        }
        if (!"todo".equals(a.getStatus())) {
            log.error(":>>> 活动自动任务不是待运行状态:{},{}", id, a.getStatus());
            throw new BusinessException("活动自动任务状态错误");
        }
        switch (a.getType()) {
            case "form":
                ActivityAutoTask up = new ActivityAutoTask();
                up.setId(id);
                up.setStatus("doing");
                boolean upResult = this.update(up);
                if (upResult) {
                    // TOOD: 执行表单任务贡献值添加
                    this.addFormQ(a);
                    up.setStatus("done");
                    this.update(up);
                }
                break;
            default:
                break;
        }
        return false;
    }

    @Override
    public Page<ActivityAutoTask> list(ActivityAutoTaskQueryVO req) {
        Query query = new Query();
        if (StringUtils.isNotBlank(req.getActivityId())) {
            query.addCriteria(Criteria.where("activityId").is(req.getActivityId()));
        }
        if (StringUtils.isNotBlank(req.getStatus())) {
            query.addCriteria(Criteria.where("status").is(req.getStatus()));
        }
        if (StringUtils.isNotBlank(req.getType())) {
            query.addCriteria(Criteria.where("type").is(req.getType()));
        }
        if (StringUtils.isNotBlank(req.getName())) {
            Pattern pattern = Pattern.compile("^.*" + req.getName() + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("name").regex(pattern));
        }
        if (StringUtils.isNotBlank(req.getOptUserId())) {
            query.addCriteria(Criteria.where("optUserId").is(req.getOptUserId()));
        }
        long count = mongoTemplate.count(query, ActivityAutoTask.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<ActivityAutoTask> infos = mongoTemplate.find(query.with(pageRequest), ActivityAutoTask.class);
        return PageableExecutionUtils.getPage(infos, pageRequest, () -> count);
    }

    @Override
    public boolean delete(String id) {
        Query q = new Query();
        q.addCriteria(Criteria.where("id").is(id).and("status").is("todo"));
        return mongoTemplate.remove(q, ActivityAutoTask.class).getDeletedCount() > 0 ? true : false;
    }

    @Override
    public boolean withdraw(String id) {
        log.info(":>>> 开始执行撤销任务:{}", id);
        ActivityAutoTask a = this.findOne(id);
        if (Objects.isNull(a)) {
            log.error(":>>> 活动自动任务不存在:{}", id);
            throw new BusinessException("活动自动任务不存在");
        }
        if (!"done".equals(a.getStatus())) {
            log.error(":>>> 活动自动任务不是完成状态:{},{}", id, a.getStatus());
            throw new BusinessException("活动自动任务状态错误");
        }
        switch (a.getType()) {
            case "form":
                ActivityAutoTask up = new ActivityAutoTask();
                up.setId(id);
                /**
                 * 状态
                 * todo:未执行
                 * doing:运行中
                 * done:完成
                 * withdrawing:撤销中
                 * withdrawed:已撤销
                 */
                up.setStatus("withdrawing");
                boolean upResult = this.update(up);
                if (upResult) {
                    // TOOD: 执行表单任务贡献值添加撤销
                    this.withdrawFormQ(a);
                    up.setStatus("withdrawed");
                    this.update(up);
                }
                break;
            default:
                break;
        }
        return false;
    }

    /**
     * 累加表单贡献值
     *
     * @param up
     */
    private void addFormQ(ActivityAutoTask up) {
        ActivityInfo activityInfo = this.activityService.findOne(up.getActivityId());
        if (Objects.isNull(activityInfo)) {
            log.error(":>>> 累加表单贡献值活动信息不存在:{}", up.getActivityId());
            return;
        }
        Query q = new Query();
        q.addCriteria(Criteria.where("activityId").is(up.getActivityId()).and("formTaskConfigId").is(up.getBizId()));
        q.addCriteria(Criteria.where("addQBizTaskId").is(null));
        Criteria criteria = null;
        if (up.getStartTime() != null || up.getEndTime() != null) {
            criteria = Criteria.where("createdTime");
            if (up.getStartTime() != null) {
                criteria.gte(up.getStartTime());
            }
            if (up.getEndTime() != null) {
                criteria.lte(up.getEndTime());
            }
            q.addCriteria(criteria);
        }
        List<UserFormTaskInfo> datas = mongoTemplate.find(q, UserFormTaskInfo.class);
        // 遍历添加贡献值
        ActivityAutoTask toUp1 = new ActivityAutoTask();
        toUp1.setId(up.getId());
        toUp1.setCount(datas.size());
        this.update(toUp1);
        for (UserFormTaskInfo uf : datas) {
            UserActivityTaskRankingAttach u = userActivityTaskRankingAttachService.find(uf.getUserId(), uf.getActivityId());
            if (Objects.isNull(u)) {
                u = new UserActivityTaskRankingAttach();
                u.setActivityId(uf.getActivityId());
                u.setUserId(uf.getUserId());
                u.setQuantity(up.getQ());
                u.setId(null);
                u.setComments("表单添加贡献值");
                u.setMobile(uf.getMobile());
                u.setType(2);
                u.setBizTaskId(up.getId());
                u.getBizTaskDetails().put(up.getId(), up.getQ());
                userActivityTaskRankingAttachService.create(u);
                continue;
            }
            UserActivityTaskRankingAttach toUp = new UserActivityTaskRankingAttach();
            toUp.setId(u.getId());
            toUp.setQuantity(up.getQ() + u.getQuantity());
            toUp.setBizTaskId(up.getId());
            toUp.getBizTaskDetails().put(up.getId(), up.getQ());
            userActivityTaskRankingAttachService.update(toUp);
        }
    }

    /**
     * 撤销累加贡献值
     *
     * @param up
     */
    private void withdrawFormQ(ActivityAutoTask up) {
        ActivityInfo activityInfo = this.activityService.findOne(up.getActivityId());
        if (Objects.isNull(activityInfo)) {
            log.error(":>>> 累加表单贡献值活动信息不存在:{}", up.getActivityId());
            return;
        }
        Query q = new Query();
        q.addCriteria(Criteria.where("activityId").is(up.getActivityId()).and("bizTaskId").is(up.getId()));
        List<UserActivityTaskRankingAttach> attaches = mongoTemplate.find(q, UserActivityTaskRankingAttach.class);
        if (CollectionUtils.isEmpty(attaches)) {
            return;
        }
        final String bizTaskId = up.getId();
        for (UserActivityTaskRankingAttach ua : attaches) {
            if (ua.getBizTaskDetails().containsKey(bizTaskId)) {
                if (ua.getBizTaskDetails().size() == 1) {
                    if (ua.getQuantity().compareTo(ua.getBizTaskDetails().get(bizTaskId)) == 0) {
                        // 删除记录
                        userActivityTaskRankingAttachService.delete(ua.getId());
                    } else {
                        Double q2 = ua.getQuantity();
                        q2 = q2 - ua.getBizTaskDetails().get(bizTaskId);
                        ua.setQuantity(q2);
                        ua.getBizTaskDetails().remove(bizTaskId);
                        userActivityTaskRankingAttachService.update(ua);
                    }
                } else {
                    Double q2 = ua.getQuantity();
                    q2 = q2 - ua.getBizTaskDetails().get(bizTaskId);
                    ua.setQuantity(q2);
                    ua.getBizTaskDetails().remove(bizTaskId);
                    userActivityTaskRankingAttachService.update(ua);
                }
            }
        }
    }
}
